package com.tsd.jxc.buy.service.impl;

import com.tsd.common.vo.BatchDeleteLogicVo;
import com.tsd.core.constants.Constants;
import com.tsd.core.thread.ThreadPoolTaskUtil;
import com.tsd.core.utils.DoubleUtil;
import com.tsd.core.utils.HlpUtils;
import com.tsd.core.utils.ListUtil;
import com.tsd.core.vo.HlpException;
import com.tsd.core.vo.PageBean;
import com.tsd.jxc.buy.dao.JxcBuyOrderDetailMapper;
import com.tsd.jxc.buy.dao.JxcBuyOrderDetailSodMapper;
import com.tsd.jxc.buy.dao.JxcBuyOrderMapper;
import com.tsd.jxc.buy.entity.JxcBuyOrderDetail;
import com.tsd.jxc.buy.entity.JxcBuyOrderDetailExt;
import com.tsd.jxc.buy.entity.JxcBuyOrderDetailSodExt;
import com.tsd.jxc.buy.entity.JxcBuyOrderExt;
import com.tsd.jxc.buy.service.JxcBuyOrderDetailService;
import com.tsd.jxc.goods.entity.JxcGoodsPriceExt;
import com.tsd.jxc.goods.service.JxcGoodsPriceService;
import com.tsd.jxc.stock.StockConstants;
import com.tsd.jxc.utils.JxcUtils;
import com.tsd.jxc.vo.JxcSettingVo;
import com.tsd.service.BaseServiceImpl;
import com.tsd.system.entity.SysUser;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 描述：JxcBuyOrderDetail 服务实现层
 *
 * @author Hillpool
 * @date 2022/07/29 15:00:45
 */
@Service
public class JxcBuyOrderDetailServiceImpl extends BaseServiceImpl implements JxcBuyOrderDetailService {

    @Resource
    private JxcBuyOrderDetailMapper jxcBuyOrderDetailMapper;
    @Resource
    private JxcBuyOrderMapper jxcBuyOrderMapper;
    @Resource
    private JxcBuyOrderDetailSodMapper jxcBuyOrderDetailSodMapper;
    @Resource
    private JxcGoodsPriceService jxcGoodsPriceService;


    @Override
    public JxcBuyOrderDetail getJxcBuyOrderDetailById(Long id) throws Exception {
        return jxcBuyOrderDetailMapper.selectByPrimaryKey(id);
    }

    @Override
    public JxcBuyOrderDetailExt queryBySid(String sid) throws Exception {
        return jxcBuyOrderDetailMapper.selectBySid(sid);
    }

    @Override
    public List<JxcBuyOrderDetailExt> queryValidByOrderList(List<String> order_list) {
        List<JxcBuyOrderDetailExt> detailExtList = ThreadPoolTaskUtil.queryInList4Split(order_list, list -> {
            JxcBuyOrderDetailExt params = new JxcBuyOrderDetailExt();
            params.setDr(0);
            params.setOrder_list(list);
            return jxcBuyOrderDetailMapper.selectByEntity(params);
        });
        if (!HlpUtils.isEmptyList(detailExtList)) {
            List<String> goodsList = ListUtil.map(detailExtList, JxcBuyOrderDetailExt::getGoods_sid);
            List<JxcGoodsPriceExt> priceExtList = jxcGoodsPriceService.queryByGoodsList(goodsList);
            for (JxcBuyOrderDetailExt detailExt : detailExtList) {
                List<JxcGoodsPriceExt> filters = ListUtil.filter(priceExtList, t -> t.getGoods_sid().equals(detailExt.getGoods_sid()));
                detailExt.setPrice_list(filters);
                detailExt.calcGoodsPrice();
            }
        }
        return detailExtList;
    }

    @Override
    public List<JxcBuyOrderDetailExt> queryValidBySidList(List<String> sid_list) {
        JxcBuyOrderDetailExt params = new JxcBuyOrderDetailExt();
        params.setDr(0);
        params.setSid_list(sid_list);
        return jxcBuyOrderDetailMapper.selectByEntity(params);
    }

    @Override
    public void deleteJxcBuyOrderDetails(List<String> list, SysUser opUser) throws Exception {
        for (String sid : list) {
            JxcBuyOrderDetail old = jxcBuyOrderDetailMapper.selectBySid(sid);
            super.checkEmpty(old, "该记录不存在");
            super.autoInjectBaseData(old, opUser, TYPE_DELETE);
            jxcBuyOrderDetailMapper.updateByPrimaryKeySelective(old);
        }
    }

    @Override
    public void saveJxcBuyOrderDetail(JxcBuyOrderDetail record, SysUser opUser) throws Exception {
        if (HlpUtils.isEmpty(record.getId())) {
            super.autoInjectBaseData(record, opUser, this.TYPE_CREATE);
            jxcBuyOrderDetailMapper.insertSelective(record);
        } else {
            super.autoInjectBaseData(record, opUser, this.TYPE_UPDATE);
            jxcBuyOrderDetailMapper.updateByPrimaryKeySelective(record);
        }
    }

    @Override
    public void saveJxcBuyOrderDetail(JxcBuyOrderExt record, boolean basePrice, SysUser opUser) throws Exception {
        List<JxcBuyOrderDetailExt> detailExtList = record.getDetail_list();
        super.checkEmptyList(detailExtList, "订单明细不能为空");

        List<Long> existIdList = ListUtil.filterMap(detailExtList, t -> !HlpUtils.isEmpty(t.getId()), JxcBuyOrderDetailExt::getId);

        JxcBuyOrderDetailExt params = new JxcBuyOrderDetailExt();
        params.setDr(0);
        params.setOrder_sid(record.getSid());
        //获取原有分录
        List<JxcBuyOrderDetailExt> oldList = jxcBuyOrderDetailMapper.selectByEntity(params);
        //是否以销定购
        boolean hasSale2Buy = ListUtil.anyMatch(detailExtList, t -> !HlpUtils.isEmpty(t.getSale_order_detail_sid()) || !HlpUtils.isEmptyList(t.getSale_order_detail_list()));

        List<JxcBuyOrderDetailSodExt> existSodList = null;
        if (hasSale2Buy) {
            JxcBuyOrderDetailSodExt sodParams = new JxcBuyOrderDetailSodExt();
            sodParams.setDr(0);
            sodParams.setBo_sid(record.getSid());
            existSodList = jxcBuyOrderDetailSodMapper.selectByEntity(sodParams);
        }

        //删除不存在订单明细
        List<JxcBuyOrderDetailExt> delList = ListUtil.filter(oldList, t -> !existIdList.contains(t.getId()));
        if (!HlpUtils.isEmptyList(delList)) {
            List<Long> delIds = ListUtil.map(delList, JxcBuyOrderDetailExt::getId);
            BatchDeleteLogicVo logicVo = new BatchDeleteLogicVo(opUser);
            logicVo.setIdList(delIds);
            jxcBuyOrderDetailMapper.deleteLogicByIdList(logicVo);

            if (hasSale2Buy) {
                List<String> delSids = ListUtil.map(delList, JxcBuyOrderDetailExt::getSid);
                List<JxcBuyOrderDetailSodExt> delSodList = ListUtil.filter(existSodList, t -> delSids.contains(t.getBod_sid()));
                if (!HlpUtils.isEmptyList(delSodList)) {
                    delIds = ListUtil.map(delSodList, JxcBuyOrderDetailSodExt::getId);
                    logicVo.setIdList(delIds);
                    jxcBuyOrderDetailSodMapper.deleteLogicByIdList(logicVo);
                }
            }
        }

        JxcSettingVo settingVo = JxcUtils.getJxcSettingVo();

        List<JxcBuyOrderDetailExt> insertList = new ArrayList<>();
        List<JxcBuyOrderDetailExt> updateList = new ArrayList<>();
        List<JxcBuyOrderDetailSodExt> insertSodList = new ArrayList<>();
        double totalQty = 0D, totalAmount = 0D, totalTaxAmount = 0D;
        for (JxcBuyOrderDetailExt detailExt : detailExtList) {
            if (HlpUtils.isEmpty(detailExt.getInvoice_state())) {
                detailExt.setInvoice_state(Constants.VALUE_NO);
            }
            if (HlpUtils.isEmpty(detailExt.getPay_req_state())) {
                detailExt.setPay_req_state(Constants.VALUE_NO);
            }
            if (HlpUtils.isEmpty(detailExt.getIn_bill())) {
                detailExt.setIn_bill(StockConstants.DETAIL_IN_OUT_BILL_NONE);
            }
            if (!HlpUtils.isEmpty(record.getSupplier_sid()) && HlpUtils.isEmpty(detailExt.getSupplier_sid())) {
                detailExt.setSupplier_sid(record.getSupplier_sid());
            }
            super.checkEmpty(detailExt.getSupplier_sid(), "第" + detailExt.getSn() + "项明细供应商不能为空");
            super.checkEmpty(detailExt.getQty(), "第" + detailExt.getSn() + "项明细数量不能为空");
            detailExt.setOrder_sid(record.getSid());
            if (basePrice) {
                super.checkEmpty(detailExt.getPrice(), "第" + detailExt.getSn() + "项明细单价不能为空");
            } else {
                super.checkEmpty(detailExt.getAmount(), "第" + detailExt.getSn() + "项明细金额不能为空");
            }
            detailExt.calc(record, settingVo, basePrice);
            totalQty = DoubleUtil.add(totalQty, detailExt.getQty());
            totalAmount = DoubleUtil.add(totalAmount, detailExt.getAmount());
            totalTaxAmount = DoubleUtil.add(totalTaxAmount, detailExt.getTax_amount());
            if (HlpUtils.isEmpty(detailExt.getId())) {
                super.autoInjectBaseData(detailExt, opUser, this.TYPE_CREATE);
                insertList.add(detailExt);
            } else {
                super.autoInjectBaseData(detailExt, opUser, this.TYPE_UPDATE);
                updateList.add(detailExt);
            }
            //处理以销定购的情况
            dealSaleToBuy(insertSodList,existSodList,record,detailExt,opUser);
        }

        if (!HlpUtils.isEmptyList(updateList)) {
            ThreadPoolTaskUtil.executeInList4Split(updateList, false, list -> jxcBuyOrderDetailMapper.updateList(list));
        }

        if (!HlpUtils.isEmptyList(insertList)) {
            ThreadPoolTaskUtil.executeInList4Split(insertList, false, list -> jxcBuyOrderDetailMapper.insertList(list));
        }

        if (hasSale2Buy && !HlpUtils.isEmptyList(insertSodList)) {
            ThreadPoolTaskUtil.executeInList4Split(insertSodList, false, list -> jxcBuyOrderDetailSodMapper.insertList(list));
        }

        record.setQty(BigDecimal.valueOf(totalQty));
        record.setAmount(BigDecimal.valueOf(totalAmount));
        record.setTax_amount(BigDecimal.valueOf(totalTaxAmount));
        double total = DoubleUtil.add(totalAmount, totalTaxAmount);
        if (!HlpUtils.isEmpty(record.getFree_shipping()) && record.getFree_shipping() == 1) {
            record.setTotal_amount(BigDecimal.valueOf(total));
        } else {
            double value = DoubleUtil.add(total, record.getReal_freight());
            record.setTotal_amount(BigDecimal.valueOf(value));
        }

        double shouldPayAmount = record.getTotal_amount().doubleValue();
        if (!HlpUtils.isEmpty(record.getIgnore_amount())) {
            shouldPayAmount = DoubleUtil.sub(shouldPayAmount, record.getIgnore_amount());
        }
        record.setShould_pay_amount(BigDecimal.valueOf(shouldPayAmount));

        double unPayAmount = record.getShould_pay_amount().doubleValue();
        if (!HlpUtils.isEmpty(record.getPaid_amount())) {
            unPayAmount = DoubleUtil.sub(unPayAmount, record.getPaid_amount());
        }
        if (unPayAmount < 0) {
            throw new HlpException("已付金额不能大于应付金额");
        }
        record.setUn_pay_amount(BigDecimal.valueOf(unPayAmount));
        if (HlpUtils.isEmpty(record.getSupplier_sid())) {
            List<String> unionSupplierList = ListUtil.map(detailExtList, JxcBuyOrderDetailExt::getSupplier_sid);
            if (unionSupplierList.size() == 1) {
                record.setSupplier_sid(unionSupplierList.get(0));
            }
        }
        jxcBuyOrderDetailMapper.updateQty4BaseByBuyOrderSid(record.getSid());
        jxcBuyOrderMapper.updateByPrimaryKeySelective(record);
    }

    /**
     * 处理以销定购的情况
     * @param insertSodList
     * @param existSodList
     * @param record
     * @param detailExt
     * @param opUser
     */
    private void dealSaleToBuy(List<JxcBuyOrderDetailSodExt> insertSodList,List<JxcBuyOrderDetailSodExt> existSodList,JxcBuyOrderExt record,JxcBuyOrderDetailExt detailExt,SysUser opUser) {
        if (!HlpUtils.isEmpty(detailExt.getSale_order_detail_sid())) {
            //构建以销定购关联表
            JxcBuyOrderDetailSodExt sodExt = ListUtil.get(existSodList, t -> t.getSod_sid().equals(detailExt.getSale_order_detail_sid()));
            if (sodExt != null) {
                return;
            }
            JxcBuyOrderDetailSodExt detailSodExt = new JxcBuyOrderDetailSodExt();
            detailSodExt.setBo_sid(record.getSid());
            detailSodExt.setBod_sid(detailExt.getSid());
            detailSodExt.setSo_sid(detailExt.getSale_order_sid());
            detailSodExt.setSod_sid(detailExt.getSale_order_detail_sid());
            super.autoInjectBaseData(detailSodExt, opUser, this.TYPE_CREATE);
            insertSodList.add(detailSodExt);
        }
        if (!HlpUtils.isEmptyList(detailExt.getSale_order_detail_list())) {
            //多个销售单合并采购的情况
            for (String orderDetailSid : detailExt.getSale_order_detail_list()) {
                String[] strings = orderDetailSid.split("_");
                if (strings.length != 2) {
                    continue;
                }
                JxcBuyOrderDetailSodExt sodExt = ListUtil.get(existSodList, t -> t.getSod_sid().equals(strings[1]));
                if (sodExt != null) {
                    continue;
                }
                JxcBuyOrderDetailSodExt detailSodExt = new JxcBuyOrderDetailSodExt();
                detailSodExt.setBo_sid(record.getSid());
                detailSodExt.setBod_sid(detailExt.getSid());
                detailSodExt.setSo_sid(strings[0]);
                detailSodExt.setSod_sid(strings[1]);
                super.autoInjectBaseData(detailSodExt, opUser, this.TYPE_CREATE);
                insertSodList.add(detailSodExt);
            }
        }
    }

    @Override
    public List<JxcBuyOrderDetailExt> findJxcBuyOrderDetails(Map<String, Object> params, PageBean page) throws Exception {
        return jxcBuyOrderDetailMapper.selectByPage(params, page);
    }

    @Override
    public List<JxcBuyOrderDetailExt> findJxcBuyOrderDetails4Select(Map<String, Object> params, PageBean page) throws Exception {
        List<JxcBuyOrderDetailExt> list = jxcBuyOrderDetailMapper.select4SelectByPage(params, page);
        if (!HlpUtils.isEmptyList(list)) {
            for (JxcBuyOrderDetailExt detailExt : list) {
//                double stockQty = DoubleUtil.sub(detailExt.getQty(), detailExt.getLock_qty());
//                if (!HlpUtils.isEmpty(detailExt.getSale_order_detail_qty())) {
//                    stockQty = DoubleUtil.add(stockQty, detailExt.getSale_order_detail_qty());
//                }
//                detailExt.setStock_qty(BigDecimal.valueOf(stockQty));
            }
        }
        return list;
    }

    @Override
    public List<JxcBuyOrderDetailExt> findJxcBuyOrderDetails(Map<String, Object> params) throws Exception {
        return jxcBuyOrderDetailMapper.selectByParams(params);
    }

    @Override
    public List<JxcBuyOrderDetailExt> queryJxcBuyOrderDetailList4Return(Map<String, Object> params, PageBean page) throws Exception {
        List<JxcBuyOrderDetailExt> detailExtList = jxcBuyOrderDetailMapper.selectValid4ReturnByPage(params, page);
        if (!HlpUtils.isEmptyList(detailExtList)) {
            List<String> goodsList = ListUtil.map(detailExtList, JxcBuyOrderDetailExt::getGoods_sid);
            List<JxcGoodsPriceExt> priceExtList = jxcGoodsPriceService.queryByGoodsList(goodsList);
            for (JxcBuyOrderDetailExt detailExt : detailExtList) {
                List<JxcGoodsPriceExt> filters = ListUtil.filterCopy(priceExtList, t -> t.getGoods_sid().equals(detailExt.getGoods_sid()), JxcGoodsPriceExt.class);
                if (!HlpUtils.isEmptyList(filters)) {
                    double qty = DoubleUtil.sub(detailExt.getQty4base(), detailExt.getReturn_qty4base());
                    double amount = DoubleUtil.sub(detailExt.getTotal_amount(), detailExt.getReturn_amount());
                    double baseUnitPrice = DoubleUtil.div(amount, qty, 4);
                    for (JxcGoodsPriceExt priceExt : filters) {
                        priceExt.setBuy_price(BigDecimal.valueOf(DoubleUtil.mul(baseUnitPrice, priceExt.getQty())));
                    }
                    List<JxcGoodsPriceExt> unitFilters = ListUtil.filterCopy(filters, t -> t.getUnit_name().equals(detailExt.getUnit_name()), JxcGoodsPriceExt.class);
                    if (!HlpUtils.isEmptyList(unitFilters)) {
                        detailExt.setUnit_qty(BigDecimal.valueOf(unitFilters.get(0).getQty()));
                    }
                }
                detailExt.setPrice_list(filters);
            }
        }
        return detailExtList;
    }

}
